package com.wwu.common.redis;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 *  Redis缓存工具类
 *  Redis支持的数据类型包含：string（字符串），hash（哈希），list（列表），set（集合）及zset(sorted set：有序集合)
 * @author 一蓑烟雨
 * @date 2021/11/15 0015 下午 19:34
 */
@Component
public class RedisUtil {
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    /**
     *  通用方法：设置指定缓存过期时间，单位秒
     * @param key  redis缓存的键
     * @param time 过期时间，单位秒
     * @return true：设置成功；false：设置失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean expire(String key,long time){
        if(time > 0){
            return redisTemplate.expire(key,time, TimeUnit.SECONDS);
        }
        return false;
    }

    /**
     *  通用方法：获取指定key的过期时间，单位秒
     * @param key redis缓存的键
     * @return 返回0代表为永久有效
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     *  通用方法：判断指定key是否存在
     * @param key redis缓存的键
     * @return true：指定key存在；false：指定key存在
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean existKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     *  通用方法：根据前缀获取所有的key
     * @param keyPrefix
     * @return java.util.Set<java.lang.String>
     * @author 一蓑烟雨
     * @date 2023/7/21 17:11
     */
    public Set<String> getKeys(String keyPrefix){
        return redisTemplate.keys(keyPrefix.concat("*"));
    }
    /**
     *  通用方法：根据指定的key删除缓存，可以传多个key
     * @param keys 一个或多个缓存的键
     * @return long 返回删除的数量
     * @author 一蓑烟雨
     * @date 2023/7/21 12:04
     */
    public long delKeys(List<String> keys) {
        if (keys != null && keys.size() > 0) {
            if (keys.size() == 1) {
               Boolean flag = redisTemplate.delete(keys.get(0));
               return flag ? 1 : 0;
            } else {
                return redisTemplate.delete(keys);
            }
        }
        return 0;
    }

    //***************************************String数据类型方法*******************************************************
    /**
     *  String数据类型：获取指定key的值
     * @param key redis缓存的键
     * @return 返回空或Object对象
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public Object getValue(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     *  String数据类型：设置指定key的值
     * @param key redis缓存的键
     * @param value redis缓存的值
     * @return true：设置缓存成功；false：设置缓存失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setValue(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  String数据类型：设置指定key的值及过期时间
     * @param key redis缓存的键
     * @param value redis缓存的值
     * @param time 单位秒，time小于等于0将设置无限制
     * @return true：设置缓存成功；false：设置缓存失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setValue(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                setValue(key, value);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  String数据类型：设置当前key的递增变量
     * @param key redis缓存的键
     * @param delta 递增因子(正整数)
     * @return 返回最后的递增变量
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long incrKey(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     *  String数据类型：设置当前key的递减变量
     * @param key redis缓存的键
     * @param delta 递减因子(正整数)
     * @return 返回最后的递减变量
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long decrKey(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    //***************************************Hash数据类型方法*********************************************************
    /**
     *  Hash数据类型：获取指定key、项目的值
     * @param key redis缓存的键
     * @param item Hash表中的项目
     * @return 返回一个对象
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public Object getHashValue(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     *  Hash数据类型：获取指定key的所有值
     * @param key redis缓存的键
     * @return 返回一个Map表
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public Map<Object, Object> getHashValues(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     *  Hash数据类型：设置指定key、项目的值
     * @param key redis缓存的键
     * @param item Hash表中的项目
     * @param value hash表中的项目值
     * @return true:表示设置成功；false:表示设置失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setHashValue(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  Hash数据类型：设置指定key、项目的值和过期时间
     * @param key redis缓存的键
     * @param item hash表中的项目
     * @param value hash表中的项目值
     * @param time 过期时间
     * @return true:表示设置成功；false:表示设置失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setHashValue(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  Hash数据类型：设置指定key、多个项目的值
     * @param key redis缓存的键
     * @param map hash表
     * @return true:表示设置成功；false:表示设置失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setHashValues(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  Hash数据类型：获取指定key、多个项目的值和过期时间
     * @param key redis缓存的键
     * @param map hash表
     * @param time 过期时间
     * @return true:表示设置成功；false:表示设置失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setHashValues(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  Hash数据类型：判断指定key、项目是否存在
     * @param key redis缓存的键
     * @param item hash表中的项目
     * @return true:表示存在；false:表示不存在
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean existHashKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     *  Hash数据类型：根据指定的key、项目删除缓存，可以传多个项目
     * @param key redis缓存的键
     * @param item hash表中的项目
     * @return java.lang.long
     * @author 一蓑烟雨
     * @date 2023/7/21 12:06
     */
    public long delHashKey(String key, HashMap<String,Object> item) {
        return redisTemplate.opsForHash().delete(key, item);
    }

    /**
     *  Hash数据类型：设置当前key、项目的递增变量
     * @param key redis缓存的键
     * @param item hash表中的项目
     * @param delta 递增因子(正整数)
     * @return 返回最后的递增变量
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public double incrHashKey(String key, String item, double delta) {
        return redisTemplate.opsForHash().increment(key, item, delta);
    }

    /**
     *  Hash数据类型：设置当前key、项目的递减变量
     * @param key redis缓存的键
     * @param item hash表中的项目
     * @param delta 递增因子(正整数)
     * @return 返回最后的递减变量
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public double decrHashKey(String key, String item, double delta) {
        return redisTemplate.opsForHash().increment(key, item, -delta);
    }

    //***************************************list数据类型方法********************************************************

    /**
     *  List数据类型：获取指定key、索引的值
     * @param key redis缓存的键
     * @param index redis缓存值集合的索引
     * @return 返回一个对象
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public Object getListValue(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     *  List数据类型：获取指定key、索引范围的值
     * @param key redis缓存的键
     * @param start 索引开始序号(索引从0开始)
     * @param end 索引结束序号
     * @return 返回一个对象集合
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public List<Object> getListValues(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     *  List数据类型：获取指定key集合的值
     * @param keys redis缓存的键集合
     * @return 返回一个对象集合
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public List<Object> getListValues(Collection<String> keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }

    /**
     *  List数据类型：获取指定key的长度
     * @param key redis缓存的键
     * @return 返回一个整数
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long getListSize(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     *  List数据类型：追加指定key的值
     * @param key redis缓存的键
     * @param value 追加的值
     * @return true:表示追加成功；false:表示追加失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setListValue(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  List数据类型：追加指定key的值及过期时间
     * @param key redis缓存的键
     * @param value 追加的值
     * @param time 过期时间
     * @return true:表示追加成功；false:表示追加失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setListValue(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  List数据类型：追加指定key的值集合
     * @param key redis缓存的键
     * @param value 追加的值集合
     * @return true:表示追加成功；false:表示追加失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setListValues(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  List数据类型：追加指定key的值集合及过期时间
     * @param key redis缓存的键
     * @param value 追加的值集合
     * @param time 过期时间
     * @return true:表示追加成功；false:表示追加失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setListValues(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  List数据类型：设置指定key、索引的值
     * @param key redis缓存的键
     * @param index redis缓存的索引
     * @param value redis缓存的值
     * @return true:表示设置成功；false:表示设置失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean setListValue(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     *  List数据类型：删除指定key的多个相同的值
     * @param key redis缓存的键
     * @param count 需要删除的数量
     * @param value redis缓存的值
     * @return 返回删除的数量
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long delListKey(String key, long count, Object value) {
        return redisTemplate.opsForList().remove(key, count, value);
    }

    //***************************************set数据类型方法*********************************************************
    /**
     *  Set数据类型：获取指定key值
     * @param key redis缓存的键
     * @return 返回一个对象
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public Object getSetValue(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     *  Set数据类型：设置指定key的值
     * @param key redis缓存的键
     * @param values redis缓存的值，可以是一个或多个
     * @return 返回一个整数
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long setSetValues(String key, Object... values) {
        return redisTemplate.opsForSet().add(key, values);
    }

    /**
     *  Set数据类型：设置指定key的值和过期时间
     * @param key redis缓存的键
     * @param time 过期时间
     * @param values redis缓存的值，可以是一个或多个
     * @return 返回一个整数
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long setSetValues(String key, long time, Object... values) {
        if (time > 0) {
            expire(key, time);
        }
        return redisTemplate.opsForSet().add(key, values);
    }

    /**
     *  Set数据类型：获取指定key的长度
     * @param key redis缓存的键
     * @return 返回一个整数
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long getSetSize(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     *  Set数据类型：判断指定key、value是否存在
     * @param key redis缓存的键
     * @param value redis缓存的值
     * @return true:表示存在；false:表示不存在
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public boolean existSetKey(String key, Object value){
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     *  Set数据类型：删除指定key、value
     * @param key redis缓存的键
     * @param values redis缓存的值，可以是一个或多个
     * @return true:表示删除成功；false:表示删除失败
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:35
     */
    public long delSetKey(String key, Object... values){
        return redisTemplate.opsForSet().remove(key, values);
    }
}
